Skip to content

Constrain where a worktree may live and skip it under headless dispatch - #113

Merged
dmccoystephenson merged 1 commit into
mainfrom
fix/worktree-location-guidance
Aug 13, 2026
Merged

Constrain where a worktree may live and skip it under headless dispatch#113
dmccoystephenson merged 1 commit into
mainfrom
fix/worktree-location-guidance

Conversation

@dmccoystephenson

Copy link
Copy Markdown
Member

Summary

  • The template recommends a git worktree for concurrent-session isolation in three places (Phase 1's adopt-a-concurrent-PR bullet, Phase 8's --delete-branch note, and the Edge cases entry) without ever stating where that worktree should be created. Under a path-restricted session — the sandbox model a headless dispatch runs under — a worktree created outside the checkout cannot be read or edited, and every subsequent file operation is refused.
  • The Edge cases entry has been given the missing constraint: the worktree belongs inside the repository checkout (e.g. .worktrees/<branch>, added to .git/info/exclude), never /tmp, and a headless dispatch should not create one at all, since such a run already owns a clone dedicated to it and has no concurrent session to collide with.
  • Phase 1's bullet has been given a pointer to that entry so the constraint is reachable from the place the workflow is first mentioned.
  • Phase 8's worktree note is left unchanged: it describes a post-merge symptom (fatal: '<branch>' is already checked out) that is correct under either placement.

.git/info/exclude was chosen over the repo's tracked .gitignore deliberately — the generated skill runs against arbitrary target repositories, and adding a line to a tracked file there would be an unrelated change smuggled into an unrelated PR.

Closes #110

Research grounding

No RESEARCH.md finding applies. This corrects an instruction whose recommended workflow is unexecutable in a known execution environment; it is an environment-accuracy fix rather than a design decision about agent behavior, and the repository's empirical findings do not speak to sandbox path scoping.

Doc sync check

  • README.md's "What it does" Step list still matches create-dev-loop.md's Steps 1:1 — no Step was added or removed; verified mechanically by scripts/check_docs.py
  • Every {{placeholder}} added or changed has a corresponding Step 4 substitution-table row — no placeholder was added or changed; verified mechanically by the same script
  • RESEARCH.md updated — not applicable; no finding is shipped or superseded here, as stated above

Test plan

  • python3 scripts/check_docs.pyDoc consistency check passed.
  • python3 -m pytest tests/ -q → 13 passed
  • Diff reviewed for the template's own conventions: no Step numbers moved, no {{placeholder}} added, no fenced code block introduced (so no triple-backtick escape is at risk), and the change is confined to prose inside the generated-skill template.
  • UNVERIFIED — behavioral anchor not run. CLAUDE.md's "Testing changes" procedure (run /create-dev-loop against a real repository and inspect the generated skill) is structurally unrunnable in this session: the sandbox is scoped to this repository's own checkout, so no second repository is reachable, and Step 6 creates a GitHub repository, which an unattended run must not do. This is the condition described in [self-audit] The repo's own validation anchor is structurally unrunnable in a headless dispatch, so template changes can never merge autonomously #109.

Because the changed file is create-dev-loop.md — template surface, and on the generated skill's do-not-auto-merge list — the Phase 4 scope gate requires the anchor, so this PR has not been merged autonomously and is handed off for human review. The changed lines are prose within the generated skill body rather than generation logic, so a fixture run would confirm the new wording appears in the output; it could not, on its own, confirm that the guidance is correct.

Deferred this cycle

Both remaining open issues were considered and deliberately not picked up:

This PR description was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).


drafted by Claude on behalf of Daniel Stephenson

The template recommended a git worktree for concurrent-session isolation
without saying where to put it. A path-restricted sandbox refuses reads and
edits outside the checkout, so a worktree in /tmp locks the session out of
its own tree. Require the worktree inside the checkout, and skip it entirely
in a headless dispatch, which already owns a dedicated clone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dmccoystephenson

Copy link
Copy Markdown
Member Author

Self-review rubric

Scored adversarially — FAIL assumed unless direct evidence of PASS was produced.

  • Scope — PASS. One file, two lines. Both are worktree-guidance lines named in Worktree guidance is unusable under gardener tend dispatch, and a run burns turns discovering it #110 (create-dev-loop.md:176 and :544 in current numbering). No formatting churn, no renames, no unrelated edits: confirmed against gh pr diff 113.
  • Tests-new — Not applicable. No Step, placeholder, or code path was added, so no new validation step is owed. The behavioral anchor could not be run at all; see the UNVERIFIED item below.
  • Tests-fix (empirical, performed rather than reasoned)FAIL. The stash-and-revalidate step was actually executed: with create-dev-loop.md reverted to origin/main, python3 scripts/check_docs.py still reported Doc consistency check passed., and the fix was then restored and the check re-run clean. The defect does not surface under the available check, which is a false negative by the rubric's definition. This is expected and structural rather than a mistake in this PR — check_docs.py covers placeholder/substitution-table parity, README-to-Step parity, and relative-link resolution, none of which can observe whether a piece of prose guidance is executable in a given environment. No fixture whose output would make this defect observable is reachable from this session, which is exactly the condition [self-audit] The repo's own validation anchor is structurally unrunnable in a headless dispatch, so template changes can never merge autonomously #109 describes. Recorded as FAIL rather than waived.
  • Sibling structure — PASS. The Edge cases addition preserves the section's **Trigger:** guidance shape and stays on one line like every neighboring entry; the Phase 1 addition is an em-dash continuation of the existing bullet, matching the surrounding bullets.
  • Sibling renames — Not applicable. Nothing was renamed.
  • Docs — PASS. A case-insensitive search for worktree across every file other than create-dev-loop.md returned no matches, so no sibling document carries a claim about worktree placement that this change could have made stale. Each row of the Phase 7 sources-of-truth table was re-checked against the diff.
  • Issue resolutionFAIL (partial). Two of the three sites Worktree guidance is unusable under gardener tend dispatch, and a run burns turns discovering it #110 names were changed. The third, Phase 8's --delete-branch note at :474, was deliberately left alone on the grounds that it describes a post-merge symptom correct under either placement — a judgment call, flagged below rather than silently taken. More materially, Worktree guidance is unusable under gardener tend dispatch, and a run burns turns discovering it #110 also asks whether a .worktrees/ directory inside the checkout interacts badly with the git clean -fdx that gardener's refresh runs. That question is not answered by this PR. A code search against the gardener repository was denied by this session's tool allow-list, so the interaction remains unverified; guessing at another project's internals was judged worse than disclosing the gap. The headless half of the risk is sidestepped, since headless runs are now told not to create a worktree at all, but an interactive worktree on a tree that gardener later refreshes remains unexamined. A follow-up issue has been filed so this does not vanish when Worktree guidance is unusable under gardener tend dispatch, and a run burns turns discovering it #110 closes.
  • Manual validation / external anchorUNVERIFIED. CLAUDE.md's "Testing changes" procedure requires running /create-dev-loop against a real repository. That is structurally unrunnable here: the sandbox is scoped to this checkout, so no second repository is reachable, and Step 6 creates a GitHub repository, which an unattended run must not do. Because template surface was modified, the Phase 4 scope gate makes the anchor required, so autonomous merge is withheld and the PR is handed to a human.
  • Placeholder-consistency — PASS. No {{placeholder}} was added, removed, or renamed; parity is enforced mechanically by scripts/check_docs.py, which passes locally and in CI.
  • Escaping — PASS. No fenced code block was introduced, so no leading-backslash escape is at stake. The added text uses inline code spans only.
  • Research-grounding — PASS. The PR body states explicitly that no RESEARCH.md finding applies. No finding is implemented, so no Implementations entry is owed.

Judgment calls left for review

  • create-dev-loop.md:474 — Phase 8's worktree note was left unchanged. It presupposes the worktree workflow, as Worktree guidance is unusable under gardener tend dispatch, and a run burns turns discovering it #110 observes, but it describes a symptom (fatal: '<branch>' is already checked out) whose accuracy does not depend on where the worktree lives. Adding a third pointer was judged noise; a reviewer preferring all three sites to be visibly consistent would be reasonable to say so.
  • create-dev-loop.md:544.git/info/exclude was recommended in preference to the target repository's tracked .gitignore. The generated skill runs against arbitrary repositories, and a tracked-file edit made for the agent's own convenience would arrive inside an otherwise unrelated PR. The trade-off is that the exclusion is per-clone and has to be re-applied.

Verification commands run

  • python3 scripts/check_docs.pyDoc consistency check passed.
  • python3 -m pytest tests/ -q13 passed
  • gh pr checks 113doc-consistency pass
  • Stash-and-revalidate, both directions, as described above.

This comment was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).


drafted by Claude on behalf of Daniel Stephenson

@dmccoystephenson

Copy link
Copy Markdown
Member Author

Follow-up filed as #114 for the half of #110 this PR does not answer: whether an in-checkout .worktrees/ directory survives the git clean -fdx in gardener's refresh. That question requires reading gardener's source, which this session's tool allow-list did not permit, and the answer would change only the same Edge cases entry touched here.

This comment was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).


drafted by Claude on behalf of Daniel Stephenson

@dmccoystephenson

Copy link
Copy Markdown
Member Author

Merge withheld

This run carried operator merge pre-authorization, and it has deliberately not been used here. Two independent gates apply:

  1. Anchor scope gate (Phase 4). create-dev-loop.md is template surface, and the behavioral anchor is UNVERIFIED for the structural reasons in [self-audit] The repo's own validation anchor is structurally unrunnable in a headless dispatch, so template changes can never merge autonomously #109. Template-surface changes require the anchor, and merge pre-authorization is not a substitute for it — the operator authorized merging, not validation.
  2. Do-not-auto-merge path match (Phase 8). create-dev-loop.md is on that list. Blanket pre-authorization given before this PR existed is not the "codeowner authorizes after being shown which protected path matched" exception, which is retrospective by construction.

The terminal state for this cycle is therefore: open, CI green, self-review posted, awaiting a human who can run /create-dev-loop against a real target repository and confirm the generated skill carries the new guidance.

This comment was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).


drafted by Claude on behalf of Daniel Stephenson

@dmccoystephenson

Copy link
Copy Markdown
Member Author

Continuation review — second dispatch

This pull request was inherited by a later Gardener dispatch as unfinished work, because the previous run was killed before it could report back. Assessment: the work itself was already complete; only the report was lost. No second branch or duplicate pull request has been opened.

Independent re-verification on the current head (8b0c57a)

  • python3 scripts/check_docs.pyDoc consistency check passed.
  • python3 -m pytest tests/ -q13 passed
  • gh pr checks 113doc-consistency pass
  • gh pr view 113 --json mergeableMERGEABLE, no conflict with main

Diff review

The full diff was re-read rather than taken on trust. Two lines change, both inside the generated-skill template.

  • create-dev-loop.md:176 — the added cross-reference resolves. The pointer text ("the concurrent-session entry in Edge cases") matches an entry that exists and is unique: grep -n "concurrent session holds the tree" create-dev-loop.md returns exactly line 544, the entry the same commit extends. A dangling pointer was the plausible failure mode here, and it is not present.
  • create-dev-loop.md:544 — the constraint is stated in the imperative shape the surrounding Edge cases entries use, stays on one line like every neighbour, and adds no fenced code block, so no leading-backslash escape is at risk. Inline code spans only.
  • No {{placeholder}} was added, removed, or renamed, so no Step 4 substitution-table row is owed — confirmed mechanically by the doc-consistency check above rather than by inspection.
  • No Step was added, removed, or renumbered, so README's "What it does" list stays 1:1 — same mechanical confirmation.
  • The third worktree mention, Phase 8's --delete-branch note at create-dev-loop.md:474, remains untouched. The prior review flagged leaving it alone as a judgment call. On re-examination that call is sound: the note describes a post-merge symptom (fatal: '<branch>' is already checked out) whose accuracy is independent of where the worktree lives, and a third pointer to the same constraint would be noise.

No new findings. The prior self-review's two self-reported FAILs (Tests-fix cannot observe this defect class; #110 answered only in part) are both accurate as written and both already tracked — by #109 and #114 respectively.

Merge readiness — withheld, second concurring judgment

This run also carried operator merge pre-authorization, and it has again not been used. The prior run's reasoning was re-derived independently rather than adopted, and it holds:

  1. Anchor scope gate (Phase 4). create-dev-loop.md is template surface, and the behavioral anchor is UNVERIFIED for the structural reasons in [self-audit] The repo's own validation anchor is structurally unrunnable in a headless dispatch, so template changes can never merge autonomously #109. Merge pre-authorization conveys permission, not validation; it cannot substitute for evidence that was never gathered.
  2. Do-not-auto-merge path match (Phase 8). create-dev-loop.md is on that list, and the codeowner exception is retrospective — it covers authorization given after a specific protected path has been surfaced, not a run-level flag set before this pull request existed.

That two consecutive dispatches each had to reconstruct this reasoning from scratch is itself a template gap, now filed as #118 with the suggested precedence wording.

Still open

#114 could not be resolved this run either, for the identical reason it was deferred before: reads outside the dispatch's own checkout are refused, so Stephenson-Software/gardener's refresh path remains unread. Both a local search for a gardener clone and a gh api search/code query were denied.

The terminal state is unchanged: open, green, reviewed twice, awaiting a human able to run /create-dev-loop against a real target repository.

This comment was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).

@dmccoystephenson
dmccoystephenson merged commit 866806c into main Aug 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Worktree guidance is unusable under gardener tend dispatch, and a run burns turns discovering it

1 participant